package com.all.proxy.handler;

import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;

/**
 * @Author LY
 * @create 2024/5/11 9:16
 * @Description Javassist动态代理实现
 */
@Slf4j
public class JavassistProxyHandler {

    private Object target;//代理目标类
    private ProxyFactory proxyFactory = new ProxyFactory();

    public JavassistProxyHandler(){}

    public JavassistProxyHandler(Object target) { //构造方法
        this.target = target;
    }

    /**
     * Javassist代理 非接口实现
     */
    public <T> T getProxy(Class<T> clazz) {
        log.info("基于Javassist动态代理 非接口实现...");
        try {
            //设置代理类的父类
            proxyFactory.setSuperclass(clazz);
            proxyFactory.setHandler(new MethodHandler() {
                /**
                 * @param self 创建的代理对象
                 * @param thisMethod 被代理方法
                 * @param proceed 如果代理接口，此参数为null，如果代理类，此参数为父类的方法
                 * @param args 方法参数
                 */
                @Override
                public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
                    log.info("Javassist动态代理|{}|{}|{}|{}", self, thisMethod, proceed, args);
                    Object invoke = proceed.invoke(self, args);
                    log.info("代理结束反参|{}", invoke);
                    return invoke;
                }
            });
            // 通过字节码技术动态创建子类实例
            return (T) proxyFactory.createClass().getDeclaredConstructor().newInstance();
        }catch (Exception e){
            log.error("javassist proxy throws exception:{}", e);
        }
        return null;
    }

    /**
     * Javassist代理 接口实现
     */
    public <T> T getProxyInterface(Class<T> clazz) {
        log.info("基于Javassist动态代理 接口实现...");
        try {
            //设置代理类的父类
            proxyFactory.setInterfaces(clazz.getInterfaces());
            proxyFactory.setHandler(new MethodHandler() {
                /**
                 * @param self 创建的代理对象
                 * @param thisMethod 被代理方法
                 * @param proceed 如果代理接口，此参数为null，如果代理类，此参数为父类的方法
                 * @param args 方法参数
                 */
                @Override
                public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
                    log.info("Javassist动态代理|{}|{}|{}|{}", self, thisMethod, proceed, args);
                    Object invoke = thisMethod.invoke(target, args);
                    log.info("代理结束反参|{}", invoke);
                    return invoke;
                }
            });
            // 通过字节码技术动态创建子类实例
            return (T) proxyFactory.createClass().getDeclaredConstructor().newInstance();
        }catch (Exception e){
            log.error("javassist proxy throws exception:{}", e);
        }
        return null;
    }
}
